import {v4 as uuidv4} from 'uuid';

function generateUUID() {
    return uuidv4();
}

function curDate() {
    return uni.$u.date(new Date(), 'yyyy-mm-dd hh:MM:ss');
}

function curTime() {
    return new Date().getTime();
}

function jsonToGetParam(json) {
    if (json) {
        return Object.keys(json).map(key => key + '=' + encodeURIComponent(json[key])).join('&');
    }
    return "";
}

function getRenderTimeInterval(messagesLength = 0) {
    if (messagesLength > 60) {
        return 300;
    }
    if (messagesLength > 40) {
        return 200;
    }
    if (messagesLength > 20) {
        return 100;
    }
    return 30;
}

const streamErrorMsg = "响应出错了，请重试！";

function streamCloseMsg(streamMsg = "") {
    if (streamMsg.trim().length === 0) {
        return streamErrorMsg;
    }
    return streamMsg;
}

const globalConfig = {
    config: {
        model: "gpt-3.5-turbo-16k",
        temperature: 0.9,
        maxTokens: 2000,
        presencePenalty: 2,
        historyMessageCount: 5,
    }
}

function newChatDefault() {
	const history = {'internal': [], 'visible': []}
    return {
        id: generateUUID(),
        topic: defaultTopic,
        lastUpdate: curDate(),
        context: [],
        messages: [],
		isChating: false, // 表示当前是否正在交流
		config: uni.$u.chat.globalConfig.config,
        requestParams: {
			'user_input': '你好',
			'history': history,
			'mode': 'chat',  //# Valid options: 'chat', 'chat-instruct', 'instruct'
			'character': 'None',
			'instruction_template': 'Chinese-Vicuna-Chat', // Chinese-Vicuna-Chat/Vigogne-Chat/MPT-Chat
			'your_name': 'DawnJun',

			// 'regenerate': false,
			// '_continue': false,
			// 'stop_at_newline': false,
			// 'chat_prompt_size': 100,
			// 'chat_generation_attempts': 1,
			// 'chat-instruct_command': 'Continue the chat dialogue below. Write a single reply for the character "<|character|>".\n\n<|prompt|>',

			'max_new_tokens': 1500,
			// 'do_sample': true,
			// 'temperature': 1.5,
			// 'top_p': 0.3,
			// 'typical_p': 1,
			// 'epsilon_cutoff': 0,  
			// 'eta_cutoff': 0,
			// 'tfs': 1,
			// 'top_a': 0,
			// 'repetition_penalty': 1.1,
			// 'top_k': 40,
			// 'min_length': 0,
			// 'no_repeat_ngram_size': 0,
			// 'num_beams': 0,
			// 'penalty_alpha': 0,
			// 'length_penalty': 1,
			// 'early_stopping': false,
			// 'mirostat_mode': 0,
			// 'mirostat_tau': 5,
			// 'mirostat_eta': 0.1,
			// 'seed': -1,
			// 'add_bos_token': true,
			// 'truncation_length': 2048,
			// 'ban_eos_token': false,
			// 'skip_special_tokens': true,
			// 'stopping_strings': []
		},
    };
}

function newMessage() {
    return {
        id: generateUUID(),
        date: curDate(),
        role: "assistant",
        content: " ",
        streaming: true,
    }
}

function newUseMessage(content) {
    return {
        id: generateUUID(),
        date: curDate(),
        role: "user",
        content: content,
        streaming: true,
    }
}

import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';

const COPY_CODE = {};
const COPY_CODE_HTML_PREV = "<a class=\"copy-btn\" code-data-index=\"";

const md = new MarkdownIt({
    html: true,
    linkify: true,
    typographer: true,
    highlight: function (code, lang) {
        const codeIndex = Date.now() + Math.floor(Math.random() * 10000000);
        COPY_CODE[codeIndex] = code;
        let html = `${COPY_CODE_HTML_PREV + codeIndex}">copy</a>`;
        const linesLength = code.split(/\n/).length - 1;
        // 生成行号
        let linesNum = '<span aria-hidden="true" class="line-numbers-rows">';
        for (let index = 0; index < linesLength; index++) {
            linesNum = linesNum + '<span></span>';
        }
        linesNum += '</span>';
        if (lang && hljs.getLanguage(lang)) {
            try {
                if (linesLength) {
                    html += '<b class="name">' + lang + '</b>';
                }
                // highlight.js 高亮代码
                const preCode = hljs.highlight(lang, code, true).value;
                return `<pre class="hljs">${html}</html><code class="language-${lang}">${preCode}</code>${linesNum}</pre>`;
            } catch (error) {
                console.log(error)
            }
        }

        const preCode = md.utils.escapeHtml(code);
        html = html + preCode;
        return `<pre class="hljs"><code>${html}</code>${linesNum}</pre>`;
    }
});

function render(streamMsg) {
    let htmlString;
    if (streamMsg.split("```").length % 2 && !streamMsg.startsWith("````") && !streamMsg.endsWith("```")) {
        htmlString = md.render(streamMsg + '  <span class="cursor">|</span>');
    } else {
        htmlString = md.render(streamMsg);
        htmlString = htmlString.replace(/(<\/code><\/pre>[^<]*)$/,
            "<span class=\"cursor cursor-color\">|</span></code></pre>");
    }
    const copyCode = getCopyCode(htmlString);
    return {
        nodes: htmlString,
        copyCode: copyCode,
    };
}

function getCopyCode(htmlString) {
    const ids = htmlString.split(COPY_CODE_HTML_PREV);
    const copyCode = {};
    if (ids && ids.length > 1) {
        for (let i = 1; i < ids.length; i++) {
            const idEndIndex = ids[i].indexOf("\"");
            if (idEndIndex <= 0) {
                continue;
            }
            const copyId = ids[i].substring(0, idEndIndex);
            const code = COPY_CODE[copyId];
            if (code) {
                copyCode[copyId] = code;
                delete COPY_CODE[copyId];
            }
        }
    }
    return copyCode;
}

const defaultTopic = "新的聊天";
const modelRange = [
    {value: "gpt-4", text: "gpt-4"},
    {value: "gpt-4-0314", text: "gpt-4-0314"},
    {value: "gpt-4-32k", text: "gpt-4-32k"},
    {value: "gpt-4-32k-0314", text: "gpt-4-32k-0314"},
    {value: "gpt-3.5-turbo", text: "gpt-3.5-turbo"},
    {value: "gpt-3.5-turbo-0301", text: "gpt-3.5-turbo-0301"},
    {value: "gpt-3.5-turbo-16k", text: "gpt-3.5-turbo-16k"},
];

export default {
    curTime,
    curDate,
    jsonToGetParam,
    getRenderTimeInterval,
    streamCloseMsg,
    newChatDefault,
    newMessage,
    newUseMessage,
    render,
    globalConfig,
    defaultTopic,
    modelRange,
    streamErrorMsg,
}